package org.lzuploader.model;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.lzuploader.model.account.Account;

/** This class is used to store the configuration of the program.
 * 
 * @author Emmanuel Cron
 *
 */
public final class Config implements Serializable
{
    /** Serial UID of this class. */
    private static final long serialVersionUID = -6105179828444284288L;
    
    /** The config instance. */
    private static Config instance;
    
    /** The logger for this class. */
    private static Log log = LogFactory.getLog(Config.class);
    
    /** List of servers entered by the user for this config. */
    private Map<String, Server> servers = new TreeMap<String, Server>(new CaseInsensitiveComparator());
    
    /** List of accounts. */
    private Map<String, Account> serverSelection = new HashMap<String, Account>();
    
    /** Path to World of Warcraft. */
    private String wowPath;
    
    /** Localization choosed by the user for this config. */
    private String localization = Localization.getDefaultLocale();
    
    /** Current account selected in combo of main window. */
    private String selectedAccount = "";
    
    /** User should never instantiate this class. Use {@link Config#getInstance getInstance()} instead. */
    private Config()
    {
        
    }
    
    /** Returns the localization currently chosed by the user.
     * @return A string containing the localization currently used by the user.
     */
    public String getLocalization()
    {
        return localization;
    }
    
    /** Sets a new localization for this config.
     * @param newLocalization The new localization to use.
     */
    public void setLocalization(final String newLocalization)
    {
        localization = newLocalization;
    }
    
    /** Returns the servers configured for this config.
     * @return The list of servers
     */
    public Map<String, Server> getServers()
    {
        return servers;
    }
    
    /** Returns the path to World of Warcraft in this config.
     * @return A string containing the path to World of Warcraft.
     */
    public String getWowPath()
    {
        return wowPath;
    }
    
    /** Sets a new path to World of Warcraft for this config.
     * @param newPath   The new path to World of Warcraft
     */
    public void setWowPath(final String newPath)
    {
        wowPath = newPath;
    }
    
    /** Returns an instance of this class.
     * Returns the instance of this class or creates a new one if none exists.
     * @return An instance of {@link Config}.
     */
    public static Config getInstance()
    {
        if (instance == null)
        {
            try
            {
                final FileInputStream file = new FileInputStream("lzuploader.lbf");
                final ObjectInputStream ois = new ObjectInputStream(file);
                
                log.info("Config file found, now attempting to read it.");
                
                instance = (Config) ois.readObject();
            }
            catch (final FileNotFoundException fnfe)
            {
                log.info("Could not find Config Serialization file.");
                instance = new Config();
            }
            catch (final IOException ioe)
            {
                log.warn("IOException while reading Config Serialization file: " + ioe.toString());
                instance = new Config();
            }
            catch (final ClassNotFoundException cnfe)
            {
                log.warn("ClassNotFoundException while reading Config Serialization file: " + cnfe.toString());
                instance = new Config();
            }
            catch (final ClassCastException cce)
            {
                log.warn("ClassCastException while reading Config Serialization file: " + cce.toString());
                instance = new Config();
            }
        }
        
        return instance;
    }
    
    /** Saves the class to a file so that it can be loaded later.
     * @return Wether the operation was successful or not.
     */
    public boolean save()
    {
        log.debug("Saving configuration to file.");
        
        try
        {
            final FileOutputStream fos = new FileOutputStream("lzuploader.lbf");
            final ObjectOutputStream oos = new ObjectOutputStream(fos);
            
            oos.writeObject(this);
        }
        catch (final FileNotFoundException fnfe)
        {
            log.error("FileNotFoundException while trying to write the Config Serialization file: " + fnfe.toString());
            return false;
        }
        catch (final IOException ioe)
        {
            log.error("IOException while trying to write the Config Serialization file: " + ioe.toString());
            return false;
        }
        
        return true;
    }
    
    /** Gets the current selected account in combo.
     * @return The string of what was selected in the combo when saved
     */
    public String getSelectedAccount()
    {
        return selectedAccount;
    }
    
    /** Sets the selected account in combo.
     * @param newSelection The new account to be set
     */
    public void setSelectedAccount(final String newSelection)
    {
        log.debug("Saving selected account: " + newSelection.toString());
        
        selectedAccount = newSelection;
    }
    
    /** Returns all the known server selection made on each account.
     * @return Entries represented this way: &lt;account, server&gt;
     */
    public Map<String, Account> getAccounts()
    {
        return serverSelection;
    }
}
